package com.lsh.oms.core.utils;

import com.lsh.base.common.exception.BusinessException;
import com.lsh.base.common.model.CommonResult;
import com.lsh.oms.core.constant.LoggerConstant;
import com.lsh.oms.core.model.http.HttpMessage;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.http.*;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;

import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 *
 * @author panxudong
 * @date 16/12/26
 */
public class HttpUtils {

    private static RequestConfig defaultRequestConfig;

    private static final int DEFAULT_MAX_TIMEOUT = 60000;

    private static final Header[] DEFAULT_HEADERS_WITH_CONTENT_TYPE;

    private static final Header[] DEFAULT_HEADERS;

    private static final Logger logger = Logger.getLogger(HttpUtils.class);

    static {
        RequestConfig.Builder configBuilder = RequestConfig.custom();
        // 设置连接超时
        configBuilder.setConnectTimeout(DEFAULT_MAX_TIMEOUT);
        // 设置读取超时
        configBuilder.setSocketTimeout(DEFAULT_MAX_TIMEOUT);
        // 设置从连接池获取连接实例的超时
        configBuilder.setConnectionRequestTimeout(DEFAULT_MAX_TIMEOUT);
        // 在提交请求之前 测试连接是否可用
        defaultRequestConfig = configBuilder.build();

        DEFAULT_HEADERS_WITH_CONTENT_TYPE = new Header[]{
                new BasicHeader("Content-type", "application/json; charset=utf-8"),
                new BasicHeader("Accept", "application/json")};

        DEFAULT_HEADERS = new Header[]{new BasicHeader("Accept", "application/json")};
    }

    private static RequestConfig getRequestConfig() {
        return defaultRequestConfig;
    }

    private static RequestConfig getRequestConfig(int maxTimeOut) {
        RequestConfig.Builder configBuilder = RequestConfig.custom();
        configBuilder.setConnectTimeout(maxTimeOut);
        configBuilder.setSocketTimeout(maxTimeOut);
        configBuilder.setConnectionRequestTimeout(maxTimeOut);
        RequestConfig requestConfig = configBuilder.build();
        return requestConfig;
    }

    public static Header[] getDefaultHeaders() {
        return DEFAULT_HEADERS.clone();
    }

    public static Header[] getDefaultHeadersWithContentType() {
        return DEFAULT_HEADERS_WITH_CONTENT_TYPE.clone();
    }

    public static CommonResult<String> post(String url, HttpEntity entity, boolean isRisk, Header... headers) throws BusinessException {
        try {
            Integer maxTimeOut = null;
            if(isRisk) {
                maxTimeOut = Integer.valueOf(30);
            }

            HttpMessage httpMessage = HttpUtils.sendPostRequest(url, entity, maxTimeOut, headers);
            String status = httpMessage.getStatus();
            String message = httpMessage.getMessage();
            if (!String.valueOf(HttpStatus.SC_OK).equals(status)) {
                String msg = "[POST][" + url + "]error response status!!! sc=" + status;
                return CommonResult.error(msg, httpMessage.getMessage());
            }
            return CommonResult.success(message);
        } catch (IOException e) {
            String message = "[POST][" + url + "]" + e.getMessage();
            logger.error(message, e);
            throw new BusinessException(CommonResult.ERROR, message);
        }
    }

    public static HttpMessage sendGetRequest(String url, Header... headers) throws IOException {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response = null;

        try {
            HttpGet httpget = new HttpGet(url);

            if(!ArrayUtils.isEmpty(headers)) {
                for (Header header : headers) {
                    httpget.setHeader(header);
                }
            }

            response = httpClient.execute(httpget);

            String status = String.valueOf(response.getStatusLine().getStatusCode());

            HttpEntity entity = response.getEntity();
            String message = entity != null? EntityUtils.toString(entity, "UTF-8"):null;

            return new HttpMessage(status, message);
        } catch (Exception e) {
            throw e;
        } finally {
            if (response != null) {
                try {
                    EntityUtils.consume(response.getEntity());
                } catch (IOException e) {
                    LoggerUtils.saveLog(" [SendGetRequest][Close entity in stream fail]" +
                                    "[Error class : " + e.getClass() + ", Error message : " + e.getMessage() + "]",
                            LoggerConstant.LOGGER_ERROR);
                    logger.error(e.getMessage(), e);
                }
            }

            try {
                httpClient.close();
            } catch (IOException e) {
                LoggerUtils.saveLog(" [SendGetRequest][Close http stream fail]" +
                                "[Error class : " + e.getClass() + ", Error message : " + e.getMessage() + "]",
                        LoggerConstant.LOGGER_ERROR);
                logger.error(e.getMessage(), e);
            }
        }
    }

    public static HttpMessage sendPostRequest(String url, List<BasicNameValuePair> pairList, Header[] headers) throws IOException {
        return sendPostRequest(url, pairList, null, headers);
    }

    public static HttpMessage sendPostRequest(String url, List<BasicNameValuePair> pairList, Integer maxTimeOut, Header... headers) throws IOException {
        StringEntity entity = new UrlEncodedFormEntity(pairList, Charset.forName("UTF-8"));
        return sendPostRequest(url, entity, maxTimeOut, headers);
    }

    public static HttpMessage sendPostRequest(String url, Header... headers) throws IOException {
        return sendPostRequest(url, new HashMap<String, Object>(), headers);
    }

    public static HttpMessage sendPostRequest(String url, String data, Header... headers) throws IOException {
        StringEntity entity = new StringEntity(data, "UTF-8");
        return sendPostRequest(url, entity, null, headers);
    }

    public static HttpMessage sendPostRequest(String url, Map<String, Object> params, Header... headers) throws IOException {
        List<BasicNameValuePair> pairList = new ArrayList<>(params.size());
        for (Map.Entry<String, Object> entry : params.entrySet()) {
            BasicNameValuePair pair = new BasicNameValuePair(entry.getKey(), entry.getValue().toString());
            pairList.add(pair);
        }

        StringEntity entity = new UrlEncodedFormEntity(pairList, Charset.forName("UTF-8"));
        return sendPostRequest(url, entity, null, headers);
    }

    private static HttpMessage sendPostRequest(String url, HttpEntity requestEntity, Integer maxTimeOut, Header[] headers) throws IOException {
        long startTime = System.currentTimeMillis();
        logger.info(" [SendPostRequest][" + url + "][Send post request start]");

        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response = null;

        HttpPost httpPost = new HttpPost(url);
        if(!ArrayUtils.isEmpty(headers)) {
            for (Header header : headers) {
                httpPost.setHeader(header);
            }
        }

        RequestConfig requestConfig;
        if(maxTimeOut == null) {
            requestConfig = HttpUtils.getRequestConfig();
        } else {
            requestConfig = HttpUtils.getRequestConfig(maxTimeOut.intValue());
        }
        httpPost.setConfig(requestConfig);
        httpPost.setEntity(requestEntity);
        try {
            response = httpClient.execute(httpPost);
            String status = String.valueOf(response.getStatusLine().getStatusCode());
            HttpEntity entity = response.getEntity();
            String message = entity != null? EntityUtils.toString(entity, "UTF-8"):null;

            return new HttpMessage(status, message);
        } catch (IOException e) {
            throw e;
        } finally {
            if (response != null) {
                try {
                    EntityUtils.consume(response.getEntity());
                } catch (IOException e) {
                    logger.error(" [SendPostRequest][Close entity in stream fail]" +
                                    "[Error class : " + e.getClass() + ", Error message : " + e.getMessage() + "]");
                    logger.error(e.getMessage(), e);
                }
            }

            try {
                httpClient.close();
            } catch (IOException e) {
                logger.error(" [SendPostRequest][Close http stream fail]" +
                                "[Error class : " + e.getClass() + ", Error message : " + e.getMessage() + "]");
                logger.error(e.getMessage(), e);
            }

            long endTime = System.currentTimeMillis();
            logger.info(" [SendPostRequest][" + url + "][Send post request end,cost:" + (endTime - startTime) + "]");
        }
    }

    public static HttpMessage sendDeleteRequest(String url) throws IOException {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response = null;

        try {
            HttpDelete httpDelete = new HttpDelete(url);

            response = httpClient.execute(httpDelete);

            String status = String.valueOf(response.getStatusLine().getStatusCode());

            HttpEntity entity = response.getEntity();
            String message = entity != null? EntityUtils.toString(entity, "UTF-8"):null;

            return new HttpMessage(status, message);
        } catch (IOException e) {
            throw e;
        } finally {
            if (response != null) {
                try {
                    EntityUtils.consume(response.getEntity());
                } catch (IOException e) {
                    LoggerUtils.saveLog(" [SendDeleteRequest][Close entity in stream fail]" +
                                    "[Error class : " + e.getClass() + ", Error message : " + e.getMessage() + "]",
                            LoggerConstant.LOGGER_ERROR);
                    logger.error(e.getMessage(), e);
                }
            }

            try {
                httpClient.close();
            } catch (IOException e) {
                LoggerUtils.saveLog(" [SendDeleteRequest][Close http stream fail]" +
                                "[Error class : " + e.getClass() + ", Error message : " + e.getMessage() + "]",
                        LoggerConstant.LOGGER_ERROR);
                logger.error(e.getMessage(), e);
            }
        }
    }

}
